#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <linux/spi/spidev.h>
#include <android/log.h>
#include "spi.h"

int spi_port[6];
unsigned int port_speed[6];

static char SPIPORTS[6][16]={"/dev/spidev0.0","/dev/spidev0.1",
                                "/dev/spidev1.0","/dev/spidev1.1",
                                "/dev/spidev2.0","/dev/spidev2.1"};

static unsigned char 	bits  = 8;
static unsigned short 	delay = 0;
static unsigned char 	mode  = SPI_MODE_0;  /* SPI Mode 0 */

int spi_open(int port, unsigned int speed)
{
	int ret = 0;

	spi_port[port] = open(SPIPORTS[port], O_RDWR);
	if( spi_port[port] < 0 ) {
		perror("unable to open spi port");
		return 1;
	}
		
    /* spi mode */
    ret = ioctl(spi_port[port], SPI_IOC_WR_MODE, &mode);
    if (ret == -1)
        perror("can't set spi mode");

    ret = ioctl(spi_port[port], SPI_IOC_RD_MODE, &mode);
    if (ret == -1)
        perror("can't get spi mode");

    /* bits per word */
    ret = ioctl(spi_port[port], SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret == -1)
        perror("can't set bits per word");

    ret = ioctl(spi_port[port], SPI_IOC_RD_BITS_PER_WORD, &bits);
    if (ret == -1)
        perror("can't get bits per word");
	
    /* max speed hz */
    ret = ioctl(spi_port[port], SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        perror("can't set max speed hz");

    ret = ioctl(spi_port[port], SPI_IOC_RD_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        perror("can't get max speed hz");

    port_speed[port] = speed;

    printf("spi mode: %d\n", mode);
    printf("bits per word: %d\n", bits);
    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

    return 0;
}

int spi_rw(int port, unsigned char *tx, unsigned char *rx, int len)
{
    int ret = 0;
    struct spi_ioc_transfer xfer;

	xfer.tx_buf = (unsigned long)tx;
	xfer.rx_buf = (unsigned long)rx;
	xfer.len = len;
	
    xfer.delay_usecs = delay;
    xfer.speed_hz = port_speed[port];
    xfer.bits_per_word = bits;
	xfer.cs_change = 0;

    /*
     * Uncomment following codes to show buffer before fed them
     * to `ioctl()`.
     */
    //const int mbc = len; // max byte count
    //char msg[1024] = {0};

    //sprintf(msg,"%s> port=%d,len=%d",__func__,port,len);
    //printf("%s\n",msg);
    //__android_log_print(ANDROID_LOG_DEBUG, "<syslib/spi>: ",  "%s", msg);

    //strcpy(msg,"TX: ");
    //for ( int i = 0 ; i < mbc ; ++i )
    //{
    //    char hex[4] = {0};
    //    if (i != (mbc-1))
    //    {
    //        sprintf(hex,"%02x ",tx[i]);
    //    }
    //    else
    //    {
    //        sprintf(hex,"%02x ",tx[len-1]);
    //    }
    //    strcat(msg,hex);
    //}
    //printf("%s\n",msg);
    //__android_log_print(ANDROID_LOG_DEBUG, "<syslib/spi>: ",  "%s",msg);

	ret = ioctl(spi_port[port], SPI_IOC_MESSAGE(1), &xfer);
    if (ret < 0) {
		perror("spi transfer error");
        return 1;
    }
    else
    {
        /*
         * Uncomment following codes to show buffer after `ioctl()`
         * operation.
         */
        //strcpy(msg,"RX: ");
        //for ( int i = 0 ; i < mbc ; ++i )
        //{
        //    char hex[4] = {0};
        //    if (i != (mbc-1))
        //    {
        //        sprintf(hex,"%02x ",rx[i]);
        //    }
        //    else
        //    {
        //        sprintf(hex,"%02x ",rx[len-1]);
        //    }
        //    strcat(msg,hex);
        //}
        //printf("%s\n",msg);
        //__android_log_print(ANDROID_LOG_DEBUG, "<syslib/spi>: ",  "%s",msg);
    }

    return 0;
}

void spi_close(int port)
{
    close(spi_port[port]);
}
